﻿using CaseManagerLibrary.Socket;
using PSDServer.Protocols;
using PSDLib.Protocols;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using CaseManagerLibrary.Http;
using PSDLib.Models;
using CaseManagerLibrary.Models;
using CaseManagerLibrary.Auth;
using CaseManagerLibrary.Log;
using System.Runtime.InteropServices;
using PSDLib;
using CaseManagerLibrary.Encrypt;

namespace PSDServer
{
    public class PSDServerContext
    {
        //private TcpManager tcpManager;
        private TcpManagerAsync tcpManager;

        public List<PSDState> DeviceList { get; set; }

        private object lock_deviceList = new object();

        //public PDMState ManagerState;
        public List<PDMState> ManagerList { get; set; }
        private object lock_managerState = new object();

        private Thread heartbeatThread;
        private Thread deviceListThread;

        public bool Working { get; private set; }

        public ILog Logger { get; set; }

        public bool RunAsService { get; private set; }

        private string versionFileRoot = "";

        public PSDServerContext(string logtype, bool runAsService)
        {
            RunAsService = runAsService;

            switch (logtype)
            {
                case "text":
                    Logger = new TextLog(Settings.LogPath);
                    break;
                case "sql":
                    Logger = new SQLiteLog(Settings.LogPath, "PSDServer", DeviceUUID.GetUUID());
                    break;
                default:
                    Logger = new ConsoleLog();
                    Logger.BringToFront = true;
                    break;
            }

            Logger.Info("创建PSDServerContext实例");
        }

        public HResult Login(string address, string username, string password)
        {
            return LoginService.Login(address, username, password);
        }

        public void Init()
        {
            Working = false;
            ManagerList = new List<PDMState>();
            DeviceList = new List<PSDState>();
            //GetDeviceList();

            //tcpManager = new TcpManager(new IPEndPoint(IPAddress.Any, Settings.TcpPort));
            var listenEP = new IPEndPoint(IPAddress.Any, Settings.ListenPort);
            var sendEP = new IPEndPoint(IPAddress.Any, Settings.SendPort);
            tcpManager = new TcpManagerAsync(listenEP);
            tcpManager.Received += TcpManager_Received;
            //tcpManager.Responsed += TcpManager_Received;
            //tcpManager.SendSuccess += TcpManager_SendSuccess;
            //tcpManager.SendFailed += TcpManager_SendFailed;

            versionFileRoot = System.Configuration.ConfigurationManager.AppSettings["VersionFileRoot"];

            if (!System.IO.Directory.Exists(versionFileRoot))
                System.IO.Directory.CreateDirectory(versionFileRoot);

            Logger.Info("初始化PSDServerContext");
        }

        private void TcpManager_SendFailed(int sent, string message, SocketState state)
        {
            if (state != null && state.SendCallback != null)
            {
                state.SendCallback(sent, message, state);
            }

            Logger.Error("Send Message Error：" + message
                + " Address=" + (state != null && state.Socket != null ? state.Socket.RemoteEndPoint.ToString() : ""));
        }

        private void TcpManager_SendSuccess(int sent, string message, SocketState state)
        {
            if (state != null && state.SendCallback != null)
            {
                state.SendCallback(sent, message, state);
            }
        }

        public void Start()
        {
            Working = true;

            heartbeatThread = new Thread(new ThreadStart(CheckDeviceHeartBeat));
            heartbeatThread.Start();

            deviceListThread = new Thread(new ThreadStart(GetDeviceList));
            deviceListThread.Start();

            tcpManager.Start();

            Logger.Info("启动PSDServer");
        }

        public void Stop()
        {
            Working = false;

            try
            {
                heartbeatThread.Abort();
            }
            catch { }


            try
            {
                deviceListThread.Abort();
            }
            catch { }

            tcpManager.Stop();
            Logger.Info("停止PSDServer");
        }

        /// <summary>
        /// 消息接收事件
        /// </summary>
        /// <param name="text"></param>
        /// <param name="remoteEp"></param>
        private void TcpManager_Received(string text, TcpClientState state)
        {
            try
            {
                MessageBase msg = MessageParser.Parse(text);

                if (msg != null)
                {
                    var processor = ServerMessageProcessor.Parse(msg);

                    processor?.Run(this, state);
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message + (ex.InnerException == null ? "" : ex.InnerException.Message) + ex.StackTrace);
            }
        }

        /// <summary>
        /// 获取设备信息列表
        /// </summary>
        private void GetDeviceList()
        {
            while (Working)
            {
                var result = HttpHelper.Get<HResult<List<dl_download_device>>>(Settings.API.GetDownloadDeviceList);

                if (result.success && result.data != null)
                {
                    Logger.Log("GetDeviceList - " + result.data.Count + " psd device:");

                    lock (lock_deviceList)
                    {
                        DeviceList.Clear();

                        foreach (var d in result.data)
                        {
                            var ds = new PSDState();
                            ds.DeviceId = d.id;
                            ds.DeviceInfo = d;
                            ds.LastHeertBeatTime = null;
                            ds.Online = false;
                            DeviceList.Add(ds);
                            Logger.Text(ds.DeviceId + "  " + ds.DeviceInfo.device_name + "  " + ds.DeviceInfo.device_ip);
                        }
                    }
                }

                Thread.Sleep(1000 * 60 * 5);
            }
        }

        private void GetDevice(string deviceId)
        {
            var result = HttpHelper.Get<HResult<dl_download_device>>(Settings.API.GetDownloadDeviceInfo + "?deviceId=" + deviceId);

            if (result.success && result.data != null)
            {
                OpenClient(result.data);
            }
        }


        /// <summary>
        /// 监测设备心跳，更新设备状态
        /// </summary>
        private void CheckDeviceHeartBeat()
        {
            while (Working)
            {
                lock (lock_deviceList)
                {
                    //循环PSD设备列表，检查最后心跳时间和当前时间超过60秒后，判定设备离线
                    foreach (var ds in DeviceList)
                    {
                        if (ds.Online)
                        {
                            if (ds.LastHeertBeatTime == null || (DateTime.Now - ds.LastHeertBeatTime.Value).TotalSeconds > 60)
                            {
                                if (ds.Online)
                                {
                                    Logger.Log("PSD Offline - " + ds.DeviceId + "  " + ds.DeviceInfo.device_name + "  " + ds.DeviceInfo.device_ip);

                                    UpdateDeviceOnlineStatus(ds.DeviceId, 0);
                                    //StopTaskByPSD(ds);
                                }
                                ds.Online = false;
                            }
                            else
                            {
                                if (!ds.Online)
                                {
                                    Logger.Log("PSD Online - " + ds.DeviceId + "  " + ds.DeviceInfo.device_name + "  " + ds.DeviceInfo.device_ip);

                                    UpdateDeviceOnlineStatus(ds.DeviceId, 1);
                                    //StartTaskByPSD(ds);
                                }
                                ds.Online = true;
                            }
                        }
                    }
                }

                lock (lock_managerState)
                {
                    //判断PDM管理端，最后心跳时间和当前时间超过60秒后，判断管理端离线
                    //if (ManagerState != null)
                    //{
                    //    if (ManagerState.LastHeertBeatTime == null || (DateTime.Now - ManagerState.LastHeertBeatTime.Value).TotalSeconds > 60)
                    //    {
                    //        if (ManagerState != null)
                    //        {
                    //            Logger.Log("PDM Offline - " + ManagerState.ManagerEP.ToString());
                    //        }
                    //        ManagerState = null;
                    //    }
                    //}

                    for (int i = ManagerList.Count - 1; i >= 0; i--)
                    {
                        if (ManagerList[i].LastHeertBeatTime == null || (DateTime.Now - ManagerList[i].LastHeertBeatTime.Value).TotalSeconds > 60)
                        {
                            Logger.Log("PDM Offline - " + ManagerList[i].ManagerEP.ToString());

                            ManagerList.RemoveAt(i);
                        }
                        //else
                        //{
                        //    Logger.Log("PDM Online - " + ManagerList[i].ManagerEP.ToString());
                        //}
                    }
                }

                Thread.Sleep(1000 * 5);
            }
        }

        private void UpdateDeviceOnlineStatus(string deviceId, int status)
        {
            Dictionary<string, string> data = new Dictionary<string, string>();
            data.Add("deviceId", deviceId);
            data.Add("status", status.ToString());
            var result = HttpHelper.Post<HResult>(Settings.API.UpdateDeviceOnlineStatus, data);
        }

        public void StartTaskByPSD(PSDState ds)
        {
            var ret = HttpHelper.Post<HResult>(Settings.API.StartDownloadTaskByPSD, new Dictionary<string, string> {
                { "deviceId", ds.DeviceId}
            });

            if (ret.success)
            {
                Logger.Log("PSD StartTask - " + ds.DeviceId + "  " + ds.DeviceInfo.device_name + "  " + ds.DeviceInfo.device_ip);
            }
            else
            {
                Logger.Error("PSD StartTask Failed - " + ds.DeviceId + "  " + ds.DeviceInfo.device_name + "  " + ds.DeviceInfo.device_ip);
            }
        }

        private void StopTaskByPSD(PSDState ds)
        {
            var ret = HttpHelper.Post<HResult>(Settings.API.StopDownloadTaskByPSD, new Dictionary<string, string> {
                { "deviceId", ds.DeviceId}
            });

            if (ret.success)
            {
                Logger.Log("PSD StopTask - " + ds.DeviceId + "  " + ds.DeviceInfo.device_name + "  " + ds.DeviceInfo.device_ip);
            }
            else
            {
                Logger.Error("PSD StopTask Failed - " + ds.DeviceId + "  " + ds.DeviceInfo.device_name + "  " + ds.DeviceInfo.device_ip);
            }
        }

        /// <summary>
        /// 登记一个PSD设备的启动信息
        /// </summary>
        /// <param name="device"></param>
        public void OpenClient(dl_download_device device)
        {
            lock (lock_deviceList)
            {
                var ds = DeviceList.Where(t => t.DeviceId == device.id).FirstOrDefault();

                if (ds != null)
                {
                    ds.DeviceInfo = device;
                    ds.LastHeertBeatTime = DateTime.Now;
                    ds.Online = true;
                }
                else
                {
                    ds = new PSDState();
                    ds.DeviceId = device.id;
                    ds.DeviceInfo = device;
                    ds.LastHeertBeatTime = DateTime.Now;
                    ds.Online = true;

                    DeviceList.Add(ds);
                }

                Logger.Log("Open Client - " + ds.DeviceId + "  " + ds.DeviceInfo.device_name + "  " + ds.DeviceInfo.device_ip + ":" + ds.DeviceInfo.device_port.ToString());

                UpdateDeviceOnlineStatus(ds.DeviceId, 1);
                //StartTaskByPSD(ds);
            }
        }

        /// <summary>
        /// 登记一个PSD设备的关闭信息
        /// </summary>
        /// <param name="deviceId"></param>
        public void CloseClient(string deviceId)
        {
            lock (lock_deviceList)
            {
                var ds = DeviceList.Where(t => t.DeviceId == deviceId).FirstOrDefault();

                if (ds != null)
                {
                    ds.LastHeertBeatTime = null;
                    ds.Online = false;

                    Logger.Log("Close Client - " + ds.DeviceId + "  " + ds.DeviceInfo.device_name + "  " + ds.DeviceInfo.device_ip + ":" + ds.DeviceInfo.device_port.ToString());

                    UpdateDeviceOnlineStatus(ds.DeviceId, 0);
                    //StopTaskByPSD(ds);
                }
            }
        }

        /// <summary>
        /// 登记一个PDM的启动信息
        /// </summary>
        /// <param name="manager"></param>
        public PDMState OpenManager(string managerIP, int managerPort)
        {
            PDMState ms = new PDMState();
            ms.ManagerEP = new IPEndPoint(IPAddress.Parse(managerIP), managerPort);
            ms.LastHeertBeatTime = DateTime.Now;

            lock (lock_managerState)
            {
                //this.ManagerState = new PDMState();
                //this.ManagerState.ManagerEP = new IPEndPoint(IPAddress.Parse(manager.manager_ip), manager.manager_port);
                //this.ManagerState.LastHeertBeatTime = DateTime.Now;

                //Logger.Log("Open Manager - " + this.ManagerState.ManagerEP.ToString());

                ManagerList.Add(ms);
            }

            Logger.Log("Open Manager - " + ms.ManagerEP.ToString());

            return ms;
        }

        /// <summary>
        /// 登记一个PDM的关闭信息
        /// </summary>
        public void CloseManager(TcpClientState state)
        {
            lock (lock_managerState)
            {
                //this.ManagerState = null;

                //Logger.Log("Close Manager");

                var ms = ManagerList.Where(t => t.ManagerEP.Address.ToString() == (state.RemoteEndPoint as IPEndPoint).Address.ToString()).FirstOrDefault();

                if (ms != null)
                {
                    ManagerList.Remove(ms);

                    Logger.Log("Close Manager - " + ms.ManagerEP.ToString());
                }
            }
        }

        public void GetPSDState(TcpClientState state)
        {
            var ms = ManagerList.Where(t => t.ManagerEP.Address.ToString() == (state.RemoteEndPoint as IPEndPoint).Address.ToString()).FirstOrDefault();

            if (ms != null)
            {
                var message = new ResponsePSDStateMessage();

                lock (lock_deviceList)
                {
                    message.PSDStateList.AddRange(this.DeviceList);
                }

                tcpManager.Send(ms.ManagerEP, message);

                Logger.Log("PDM GetPSDState - " + ms.ManagerEP.ToString());
            }
        }

        /// <summary>
        /// 更新PSD心跳状态
        /// </summary>
        /// <param name="heartbeat"></param>
        public void UpdatePSDHeartbeat(PSDHeartbeat heartbeat)
        {
            if (heartbeat != null)
            {
                var ds = DeviceList.Where(t => t.DeviceId == heartbeat.DeviceId).FirstOrDefault();

                if (ds != null)
                {
                    ds.DeviceInfo = heartbeat.DeviceInfo;
                    ds.DeviceInfo.device_ip = heartbeat.DeviceIP;
                    ds.DeviceInfo.device_port = heartbeat.DevicePort;
                    //ds.DeviceInfo.main_storage = heartbeat.MainStorage;
                    //ds.DeviceInfo.main_storage_total = heartbeat.MainStorageTotal;
                    //ds.DeviceInfo.main_storage_free = heartbeat.MainStorageFree;
                    //ds.DeviceInfo.second_storage = heartbeat.SecondaryStorage;
                    //ds.DeviceInfo.second_storage_total = heartbeat.SecondaryStorageTotal;
                    //ds.DeviceInfo.second_storage_free = heartbeat.SecondaryStorageFree;
                    ds.LastHeertBeatTime = DateTime.Now;

                    if (!ds.Online)
                    {
                        UpdateDeviceOnlineStatus(ds.DeviceId, 1);
                    }
                    ds.Online = true;

                    Logger.Log("Update PSD Heartbeat - " + ds.DeviceId + "  " + ds.DeviceInfo.device_name
                        + "  " + ds.DeviceInfo.device_ip + ":" + ds.DeviceInfo.device_port.ToString() + "  " + ds.LastHeertBeatTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
                }
                else
                {
                    GetDevice(heartbeat.DeviceId);
                }
            }
        }

        /// <summary>
        /// 更新PDM心跳状态
        /// </summary>
        /// <param name="heartbeat"></param>
        public void UpdatePDMHeartbeat(PDMHeartbeat heartbeat)
        {
            if (heartbeat != null)
            {
                var ms = ManagerList.Where(t => t.ManagerEP.Address.ToString() == heartbeat.ManagerIP).FirstOrDefault();

                if (ms == null)
                {
                    ms = OpenManager(heartbeat.ManagerIP, heartbeat.ManagerPort);
                }
                else
                {
                    lock (lock_managerState)
                    {
                        //if (ManagerState == null)
                        //{
                        //    ManagerState = new PDMState();
                        //}
                        //ManagerState.ManagerEP = new IPEndPoint(IPAddress.Parse(heartbeat.ManagerIP), heartbeat.ManagerPort);
                        //ManagerState.LastHeertBeatTime = DateTime.Now;

                        ms.ManagerEP = new IPEndPoint(IPAddress.Parse(heartbeat.ManagerIP), heartbeat.ManagerPort);
                        ms.LastHeertBeatTime = DateTime.Now;
                    }
                }

                Logger.Log("Update PDM Heartbeat - " + ms.ManagerEP.ToString() + "  " + ms.LastHeertBeatTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
            }
        }

        /// <summary>
        /// 通知PSD设备设置存储位置
        /// </summary>
        /// <param name="msg"></param>
        public void PSDSetStorage(SetStorageMessage msg)
        {
            var ds = DeviceList.Where(t => t.DeviceId == msg.DeviceId && t.Online == true).FirstOrDefault();

            if (ds != null && ds.DeviceInfo != null)
            {
                var deviceEp = new IPEndPoint(IPAddress.Parse(ds.DeviceInfo.device_ip), ds.DeviceInfo.device_port);

                tcpManager.Send(deviceEp, msg);
            }
        }

        /// <summary>
        /// 通知PSD设备开始下载
        /// </summary>
        public void PSDStartDownload(StartDownloadMessage msg)
        {
            var ds = DeviceList.Where(t => t.DeviceId == msg.DeviceId && t.Online == true).FirstOrDefault();

            if (ds != null && ds.DeviceInfo != null)
            {
                var deviceEp = new IPEndPoint(IPAddress.Parse(ds.DeviceInfo.device_ip), ds.DeviceInfo.device_port);

                tcpManager.Send(deviceEp, msg);


            }
        }

        /// <summary>
        /// 通知PSD设备停止下载
        /// </summary>
        /// <param name="deviceId"></param>
        public void PSDStopDownload(StopDownloadMessage msg)
        {
            var ds = DeviceList.Where(t => t.DeviceId == msg.DeviceId && t.Online == true).FirstOrDefault();

            if (ds != null && ds.DeviceInfo != null)
            {
                var deviceEp = new IPEndPoint(IPAddress.Parse(ds.DeviceInfo.device_ip), ds.DeviceInfo.device_port);

                tcpManager.Send(deviceEp, msg);
            }
        }

        /// <summary>
        /// 通知PSD设备开始刻录
        /// </summary>
        public void PSDStartBurnDVD(StartBurnDVDMessage msg)
        {
            var ds = DeviceList.Where(t => t.DeviceId == msg.DeviceId && t.Online == true).FirstOrDefault();

            if (ds != null && ds.DeviceInfo != null)
            {
                var deviceEp = new IPEndPoint(IPAddress.Parse(ds.DeviceInfo.device_ip), ds.DeviceInfo.device_port);

                tcpManager.Send(deviceEp, msg);
            }
        }

        public void SetPSDName(SetPSDNameMessage msg)
        {
            var ds = DeviceList.Where(t => t.DeviceId == msg.DeviceId && t.Online == true).FirstOrDefault();

            if (ds != null && ds.DeviceInfo != null)
            {
                string oldName = ds.DeviceInfo.device_name;

                ds.DeviceInfo.device_name = msg.DeviceName;

                var deviceEp = new IPEndPoint(IPAddress.Parse(ds.DeviceInfo.device_ip), ds.DeviceInfo.device_port);

                tcpManager.Send(deviceEp, msg);

                Logger.Log("Set PSD DeviceName - " + ds.DeviceId + "  " + ds.DeviceInfo.device_ip + "  Set Name：" + oldName + "—>" + msg.DeviceName);
            }
        }

        public void SetPSDMaxDownloadProcess(SetPSDMaxDownloadProcessMessage msg)
        {
            var ds = DeviceList.Where(t => t.DeviceId == msg.DeviceId && t.Online == true).FirstOrDefault();

            if (ds != null && ds.DeviceInfo != null)
            {
                int oldProcess = ds.DeviceInfo.max_download_process;

                ds.DeviceInfo.max_download_process = msg.Process;

                var deviceEp = new IPEndPoint(IPAddress.Parse(ds.DeviceInfo.device_ip), ds.DeviceInfo.device_port);

                //tcpManager.Send(deviceEp, msg);

                tcpManager.Send(deviceEp, msg);

                Logger.Log("Set PSD MaxDownloadProcess - " + ds.DeviceId + "  " + ds.DeviceInfo.device_ip + "  Set Process：" + oldProcess.ToString() + "—>" + msg.Process.ToString());

            }
        }

        public void BurnJobDenied(BurnJobDeniedMessage msg)
        {
            foreach (var ms in ManagerList)
            {
                tcpManager.Send(ms.ManagerEP, msg);
            }
        }

        public void TestConnection(string ip, TcpClientState state)
        {
            var data = System.Text.Encoding.UTF8.GetBytes("success");

            state.TcpClient.Client.Send(data);
        }

        public void UploadVersionFile(UploadVersionFileMessage msg, IPEndPoint remoteEp)
        {
            VersionFileReceivedMessage recvMsg = new VersionFileReceivedMessage();

            System.IO.FileStream fs = null;

            try
            {
                string fileFolder = System.IO.Path.Combine(versionFileRoot, msg.Version, msg.FilePath);
                string filePath = System.IO.Path.Combine(fileFolder, msg.FileName);
                if (!System.IO.Directory.Exists(fileFolder))
                    System.IO.Directory.CreateDirectory(fileFolder);

                fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create, System.IO.FileAccess.Write);

                fs.Write(msg.FileData, 0, msg.FileData.Length);

                fs.Close();

                if (FileValidHelper.GetFileSHA1(filePath) == msg.FileSign)
                {
                    recvMsg.Success = true;
                }
                else
                {
                    recvMsg.Success = false;
                    recvMsg.Message = "文件SHA1校验失败";
                }
            }
            catch (Exception ex)
            {
                recvMsg.Success = false;
                recvMsg.Message = ex.Message + (ex.InnerException != null ? ex.InnerException.Message : "");
            }
            finally
            {
                if (fs != null)
                {
                    fs.Dispose();
                }

                tcpManager.Send(remoteEp, recvMsg);
            }
        }

        public void DownloadVersionFile(DownloadVersionFileMessage msg, IPEndPoint remoteEp)
        {
            VersionFileMessage fileMsg = new VersionFileMessage();
            System.IO.FileStream fs = null;
            try
            {
                fs = new System.IO.FileStream(msg.FilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
                fileMsg.FileData = new byte[Convert.ToInt32(fs.Length)];
                fs.Read(fileMsg.FileData, 0, fileMsg.FileData.Length);
                fs.Close();

                fileMsg.FilePath = msg.FilePath.Replace(versionFileRoot, "");
                string[] temp = fileMsg.FilePath.Split("\\".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                fileMsg.Version = temp[0];
                fileMsg.FileName = temp[temp.Length - 1];
                fileMsg.Success = true;
            }
            catch (Exception ex)
            {
                fileMsg.Success = false;
                fileMsg.Message = ex.Message + (ex.InnerException != null ? ex.InnerException.Message : "");
            }
            finally
            {
                if (fs != null)
                {
                    fs.Dispose();
                }

                tcpManager.Send(remoteEp, fileMsg);
            }
        }
    }
}
